package main

import (
	"container/list"
	"fmt"
	"github.com/axgle/mahonia"
	"github.com/gorilla/websocket"
	"io"
	"net"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"
)

type 同步客户端 struct {
	*websocket.Conn
	同步锁 sync.RWMutex
	编号 string
}
//var 客户端组 map[string]*同步客户端
var 客户端列表 *list.List

func main() {
	//客户端组 = make(map[string]*同步客户端)
	客户端列表 = list.New()

	http.HandleFunc("/ws", 分类客户端)
	//服务端启动
	go	http.ListenAndServe("0.0.0.0:9999", nil)
	// 创建监听
	socket, err := net.ListenUDP("udp", &net.UDPAddr{
		IP:   net.IPv4(0, 0, 0, 0),
		Port: 7777,
	})
	if err != nil {
		fmt.Println("监听失败!", err)
		return
	}
	defer socket.Close()
	for {
		// 读取数据
		数据 := make([]byte, 4096)
		长度, 客户地址, err := socket.ReadFromUDP(数据)
		if err != nil {
			fmt.Println("读取数据失败!", err)
			continue
		}
		go 保存日志(长度, 客户地址, 数据[:长度] )

	}
}

func 转码(src string, srcCode string, tagCode string) string {
	srcCoder := mahonia.NewDecoder(srcCode)
	srcResult := srcCoder.ConvertString(src)
	tagCoder := mahonia.NewDecoder(tagCode)
	_, cdata, _ := tagCoder.Translate([]byte(srcResult), true)
	result := string(cdata)
	return result
}

func 保存日志(read int,addr *net.UDPAddr,data []byte)  {
	st:= 转码(string(data), "GBK", "UTF-8")
	str := strings.Split(st,"!@!")

	if len(str) > 1 {
		_ = 写文件(str[0]+".log",st[len(str[0])+3:] )
		转发日志(str[0],st[len(str[0])+3:])

	}

	fmt.Println(addr,read, 转码(string(data),"GBK","UTF-8") )
}

const (
	日志路径 = "log/"
	格式 = "20060102"
	换行 = "\r\n"
)

func 写文件(文件名, msg string) error {
	//以天为基准,存日志
	var 路径 = 日志路径 + time.Now().Format(格式) + "/"
	if !存在目录(路径) {
		return 创建目录(路径)
	}
	var (
		err error
		f   *os.File
	)

	f, err = os.OpenFile(路径+文件名, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	_, err = io.WriteString(f, 换行+msg)

	defer f.Close()
	return err
}

func 创建目录(path string) error {
	err := os.MkdirAll(path, os.ModePerm)
	if err != nil {
		return err
	}
	os.Chmod(path, os.ModePerm)
	return nil
}

func 存在目录(f string) bool {
	_, err := os.Stat(f)
	return err == nil || os.IsExist(err)
}

var(
	协议升级 = websocket.Upgrader{
		//允许跨域访问
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}
)


func 分类客户端(w http.ResponseWriter, r *http.Request) {

	var (
		conn *websocket.Conn
		err error
		data []byte
		ws *同步客户端
		eee *list.Element
	)
	if conn, err = 协议升级.Upgrade(w, r, nil); err !=nil {
		//报错了，直接返回底层的websocket链接就会终断掉
		return
	}
	z := r.URL.String()
	if len(z)>4 {
		ws = new(同步客户端)
		ws.Conn = conn
		ws.编号 = z[4:]
		eee = 客户端列表.PushBack(ws)
		fmt.Println("ws客户连接", z[4:])
	}

	//得到了websocket.Conn长连接的对象，实现数据的收发
	for {
		if _, data, err = conn.ReadMessage(); err != nil {
			goto ERR
		}
		if err = conn.WriteMessage(websocket.TextMessage, data); err != nil {
			goto ERR
		}
	}
	//error的标签
ERR:
	conn.Close()
	if len(z)>4 {
		客户端列表.Remove(eee)
	}

}
func 转发日志(id string,msg string)  {
	for 客户端 := 客户端列表.Front();客户端!=nil;客户端=客户端.Next() {
		客户:=客户端.Value.(*同步客户端)
	 if 客户.编号 == id{
		 客户.同步锁.Lock()
		 if err := 	客户.Conn.WriteMessage(websocket.TextMessage, []byte(msg)); err != nil {
			 客户.同步锁.Unlock()
			 //报错了
			 客户端列表.Remove(客户端)
		 }else {
			 客户.同步锁.Unlock()
		 }
	 }

	}
}



